package awk.script.javassist;

import javassist.*;
import javassist.bytecode.ClassFile;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author: lux
 * @date: 2017/10/25 14:54
 */
public class CtClassTest {

    public static ClassPool classPool = ClassPool.getDefault();

    public static void main(String[] args) {
        String packageName = "awk.script.javassist";
        String className = "TestClass02";
        makeClass(packageName,className);
        Object result = execCtMethod(packageName, className);
        System.out.println(result);
    }

    /**
     * CtMethod（...）源代码：
     * public CtMethod(
     * CtClass returnType,//这个方法的返回值类型，
     * String mname, //（method name）方法的名字是什么
     * CtClass[] parameters, //方法传入的参数类型是什么
     * CtClass declaring //添加到哪个类中
     * ) {....}
     *
     * @throws CannotCompileException
     * @throws IOException
     */
    public static void makeClass(String packageName,String className) {
        try {
            CtClass ctClass = classPool.makeClass(packageName + "." + className);
            CtClass[] parameters = new CtClass[]{classPool.get(String[].class.getName())};
//            CtMethod mainMethod = new CtMethod(CtClass.voidType, "main", parameters, ctClass);
//            mainMethod.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
//            mainMethod.setBody("{\n==" +
//                    "\t\tSystem.out.println(\"hello,xdf,this my test01\");\n" +
//                    "\t\tSystem.out.println(\"你好世界\");\n" +
//                    "\t}");
            //也可以直接加载方法字符串
            CtMethod mainMethod =CtMethod.make(
                    "public static void main(String[] args) {\n" +
                            "\t\tSystem.out.println(\"hello,xdf,this my test01\");\n" +
                            "\t\tSystem.out.println(\"你好世界\");\n" +
                            "\t}",
                    ctClass
            );
            ctClass.addMethod(mainMethod);

            //输出类的内容
//            ctClass.writeFile();
//            ctClass.detach();
            //或者生成到指定目录,将ctClass生成字节数组，并写入文件
            //FileUtil.touch("/Users/yujianlong/Movies/test3/test.class");

            //FileUtil.writeBytes(ctClass.toBytecode(),"/Users/yujianlong/Movies/test3/test.class");
            //或者
//            FileOutputStream output = new FileOutputStream("/Users/yujianlong/Movies/test3/test.class");
//            output.write(ctClass.toBytecode());
//            output.close();
        } catch (NotFoundException | CannotCompileException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 执行方法
     */
    public static Object execCtMethod(String packageName,String className) {
        try {
            CtClass cc = classPool.get(packageName + "." + className);
            Class<?> aClass = cc.toClass();
            Object instance = aClass.newInstance();

            return aClass.getDeclaredMethod("main",  String[].class).invoke(instance, new Object[]{new String[]{"A", "B", "C"}});
        } catch (NotFoundException | CannotCompileException | IllegalAccessException | InvocationTargetException |
                 InstantiationException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

}

